/* 命令式编程 VS 函数式编程 */
~function fn1() {
  // 命令式编程
  // var array = [0, 1, 2, 3];
  // for (let i = 0; i < array.length; i++) {
  //   array[i] = Math.pow(array[i], 2);
  // }
  // console.log(array);

  // 函数式方式
  let array = [0, 1, 2, 3];
  array = array.map((item) => Math.pow(item, 2));
  console.log(array);
};

/* 纯函数  */
/* 
函数内部传入指定的值，就会返回确定唯一的值
不会造成【超出作用域的变化】，例如修改全局变量或引用传递的参数
-----
便于测试
不依赖外部环境计算，不会产生【副作用】，提高函数的【复用性】
可读性更强 ，函数不管是否是纯函数 都会有一个语义化的名称，更便于阅读
可以组装成复杂任务的可能性。符合模块化概念及【单一职责原则】
*/
function fn2() {
  let a = 100;
  function dirtyFn() {
    a *= 2;
  }
  function pureFn(arg) {
    return arg * 2;
  }
  console.log(pureFn(a)); //200
}

/* 高阶函数：以函数作为输入或者输出的函数被称为高阶函数 */
function fn3() {
  /* 以函数作为入参 */
  const forEach = function (arr, handlerFn) {
    for (let i = 0; i < arr.length; i++) {
      handlerFn(arr[i]);
    }
  };

  let arr = [1, 2, 3];
  forEach(arr, (item) => {
    console.log(item);
  });

  /* 银行账户闭包 */
  function account(money) {
    /* 返回值是函数的组合 */
    return {
      save(n) {
        money += n;
      },
      withdraw(n) {
        money -= n;
        return money;
      },
    };
  }
}
// fn3()

/* 利用闭包做缓存介质 */
/* 潜在月考题：实现一个只能调用一次的函数 */
function fn4() {
  /* 将入参的函数变成一个只能被执行一次的函数 */
  const once = (fn) => {
    // 存储内层函数的私有数据
    // 记录内层函数是否被调用过
    let used = false;

    /* add函数进去 一次性的add函数出来 */
    /* 调用oncedAdd即等于调用当前函数 */
    return function (...args) {
      /* 如果fn未调用过 */
      if (!used) {
        // 调用真正的add(2,3)
        let ret = fn(...args);
        // 现在add是一个二手的add了
        used = true;
        return ret;
      } else {
        console.log("a used gun");
      }
    };
  };

  /* add函数进去 一次性的add函数出来 */
  const add = (a, b) => a + b;
  const oncedAdd = once(add);

  console.log(oncedAdd(2, 3)); //5
  console.log(oncedAdd(4, 5)); //
}
// fn4();

function fn42() {
  const once = (fn) => {
    let used = false;

    return function (...args) {
      if (used) {
        console.log("不得调用一个二手函数");
      } else {
        let ret = fn(...args);
        used = true;
        return ret;
      }
    };
  };

  const add = (a, b) => a + b;
  const oncedAdd = once(add);

  console.log(oncedAdd(2, 3)); //5
  console.log(oncedAdd(4, 5)); //5
}
